package com.link2room.bumblebee.facade.impl;

import com.link2room.bumblebee.dto.param.base.CodeBaseParamDto;
import com.link2room.bumblebee.dto.result.base.CodeBaseDto;
import com.link2room.bumblebee.facade.ICodeBaseFacadeService;
import com.link2room.common.constant.DefaultValue;
import com.link2room.common.entity.BaseEntity;
import com.link2room.common.enums.BaseSysExceptionEnum;
import com.link2room.common.exception.SysException;
import com.link2room.common.jpa.condition.ConditionDetail;
import com.link2room.common.jpa.condition.L2RCondition;
import com.link2room.common.jpa.criteria.CriteriaUtil;
import com.link2room.common.jpa.result.QueryResult;
import com.link2room.common.service.ICommonService;
import com.link2room.common.util.ClassConverUtil;
import com.link2room.common.util.L2RAssert;
import com.link2room.bumblebee.entity.CodeBaseEntity;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * Created by LN on 2017/3/7.
 */
@Component("codeBaseFacadeService")
public class CodeBaseFacadeServiceImpl implements ICodeBaseFacadeService {
    @Resource
    private ICommonService commonServiceSupport;
    @Override
    public List<CodeBaseDto> findByCode(CodeBaseParamDto paramDto) throws Exception {
        String lhotelGroupCode = paramDto.getLhotelGroupCode();
        L2RAssert.stringBlank(lhotelGroupCode,"[lhotelGroupCode] is null");
        List<String> codes = paramDto.getCodes();
        if(codes == null || codes.size() == 0){
            throw new SysException(
                    BaseSysExceptionEnum.INVALID_PARA.getCode(),
                    BaseSysExceptionEnum.INVALID_PARA.getMsg() +" [codes]:"+codes+"is required",
                    BaseSysExceptionEnum.INVALID_PARA.getBizType());
        }
        List<CodeBaseDto> res = new ArrayList<>();
        L2RCondition l2RCondition=new L2RCondition();
        l2RCondition.setAndConditions(new ConditionDetail[]{
                //new ConditionDetail(BaseEntity.BaseEntity_.lhotelGroupCode.toString(), CriteriaUtil.Operator.EQ, lhotelGroupCode),
                new ConditionDetail(BaseEntity.BaseEntity_.isHalt.toString(), CriteriaUtil.Operator.EQ, DefaultValue.F),
                new ConditionDetail(CodeBaseEntity.CodeBaseEntity_.code.toString(), CriteriaUtil.Operator.IN, codes),
        });

        QueryResult<CodeBaseEntity> codeBaseQueryResults = commonServiceSupport.findAllByCondition(CodeBaseEntity.class, l2RCondition);
        if(codeBaseQueryResults != null && codeBaseQueryResults.getTotalrecord() > 0){
            res = codeBaseQueryResults.getResultlist().stream()
                    .map(entity -> ClassConverUtil.copyProperties(entity, CodeBaseDto.class))
                    .collect(Collectors.toList());
        }
        return res;
    }

    @Override
    public List<CodeBaseDto> findByCodeAsRoot(CodeBaseParamDto paramDto) throws Exception {
        String lhotelGroupCode = paramDto.getLhotelGroupCode();
        L2RAssert.stringBlank(lhotelGroupCode,"[lhotelGroupCode] is null");
        List<String> codes = paramDto.getCodes();
        if(codes == null || codes.size() == 0){
            throw new SysException(
                    BaseSysExceptionEnum.INVALID_PARA.getCode(),
                    BaseSysExceptionEnum.INVALID_PARA.getMsg() +" [codes]:"+codes+"is required",
                    BaseSysExceptionEnum.INVALID_PARA.getBizType());
        }
        return codes.stream()
                .map(parentCode -> findCodeTree(lhotelGroupCode, parentCode))
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    private CodeBaseDto findCodeTree(String lhotelGroupCode ,String parentCode){
        CodeBaseDto root = selectRootNode(lhotelGroupCode, parentCode);
        return selectChildren(root);

    }

    private CodeBaseDto selectRootNode(String lhotelGroupCode ,String parentCode)  {
        L2RAssert.stringBlank(lhotelGroupCode, "[lhotelGroupCode] is null;");
        L2RAssert.stringBlank(parentCode, "[parentCode] is null;");
        CodeBaseDto rootDto ;
        CodeBaseEntity findRoot = new CodeBaseEntity();
        findRoot.setCode(parentCode);
        //findRoot.setLhotelGroupCode(lhotelGroupCode);
        findRoot.setIsHalt(DefaultValue.F);
        CodeBaseEntity rootEntity = null;
        try {
            rootEntity = commonServiceSupport.findOneEQ(CodeBaseEntity.class, findRoot);
        } catch (Exception e) {
            throw new SysException(BaseSysExceptionEnum.BASE_FUCATION_OPTION,e);
        }
        if(rootEntity == null){
            return null;
        }else {
            return ClassConverUtil.copyProperties(rootEntity,CodeBaseDto.class);
        }
    }

    private CodeBaseDto selectChildren(CodeBaseDto rootNode)  {
        if(rootNode == null){
            return null;
        }
        CodeBaseEntity findChildren = new CodeBaseEntity();
        findChildren.setLhotelGroupCode(rootNode.getLhotelGroupCode());
        findChildren.setParentCode(rootNode.getCode());
        findChildren.setIsHalt(DefaultValue.F);
        QueryResult<CodeBaseEntity> queryRes = null;
        try {
            queryRes = commonServiceSupport.findAllEQ(CodeBaseEntity.class, findChildren);
        } catch (Exception e) {
            throw new SysException(BaseSysExceptionEnum.BASE_FUCATION_OPTION,e);
        }
        if(queryRes==null || queryRes.getResultlist() == null || queryRes.getResultlist().size() == 0){
            return rootNode;
        }
        List<CodeBaseDto> children = queryRes.getResultlist().stream()
                .map(entity -> ClassConverUtil.copyProperties(entity, CodeBaseDto.class))
                .collect(Collectors.toList());
        rootNode.setChildren(children);
        children.forEach(this::selectChildren);
        return rootNode;
    }
}
